<html>
<head>
  <title>collections</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="671"/>
<h1>collections</h1>

<div>
<span><div><h4><font style="font-size: 16pt; color: rgb(28, 51, 135);">collections</font></h4><div>collections是Python内建的一个集合模块，提供了许多<font style="color: rgb(255, 0, 0);"><b>有用的集合类</b></font>。</div><div><br/></div><h3><font style="font-size: 12pt; color: rgb(227, 0, 0);">namedtuple</font></h3><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">我们知道</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">可以表示不变集合，例如，一个点的二维坐标就可以表示成：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; p = (1, 2)</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">但是，看到</span><span style="-en-paragraph: true;">(1, 2)</span><span style="-en-paragraph: true;">，很难看出这个</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">是用来表示一个坐标的。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">定义一个class又小题大做了，这时，</span><span style="-en-paragraph: true;">namedtuple</span><span style="-en-paragraph: true;">就派上了用场：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; from collections import namedtuple</div><div>&gt;&gt;&gt; Point = namedtuple('Point', ['x', 'y'])</div><div>&gt;&gt;&gt; p = Point(1, 2)</div><div>&gt;&gt;&gt; p.x</div><div>1&gt;&gt;&gt; p.y</div><div>2</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">namedtuple</span><span style="-en-paragraph: true;">是一个函数，它用来创建一个自定义的</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">对象，并且规定了</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">元素的个数，并可以用属性而不是索引来引用</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">的某个元素。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">这样一来，我们用</span><span style="-en-paragraph: true;">namedtuple</span><span style="-en-paragraph: true;">可以很方便地定义一种数据类型，它具备tuple的不变性，又可以根据属性来引用，使用十分方便。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">可以验证创建的</span><span style="-en-paragraph: true;">Point</span><span style="-en-paragraph: true;">对象是</span><span style="-en-paragraph: true;">tuple</span><span style="-en-paragraph: true;">的一种子类：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; isinstance(p, Point)</div><div>True&gt;&gt;&gt; isinstance(p, tuple)</div><div>True</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">类似的，如果要用坐标和半径表示一个圆，也可以用</span><span style="-en-paragraph: true;">namedtuple</span><span style="-en-paragraph: true;">定义：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div># namedtuple('名称', [属性list]):</div><div>Circle = namedtuple('Circle', ['x', 'y', 'r'])</div></div><h3><font style="font-size: 12pt; color: rgb(227, 0, 0);"><br/></font></h3><h3><span style="color: rgb(227, 0, 0); font-size: 12pt; line-height: 1.45;">deque</span><br/></h3><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">使用</span><span style="-en-paragraph: true;">list</span><span style="-en-paragraph: true;">存储数据时，按索引访问元素很快，但是插入和删除元素就很慢了，因为</span><span style="-en-paragraph: true;">list</span><span style="-en-paragraph: true;">是线性存储，数据量大的时候，插入和删除效率很低。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">deque是为了高效实现插入和删除操作的双向列表，适合用于队列和栈：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; from collections import deque</div><div>&gt;&gt;&gt; q = deque(['a', 'b', 'c'])</div><div>&gt;&gt;&gt; q.append('x')</div><div>&gt;&gt;&gt; q.appendleft('y')</div><div>&gt;&gt;&gt; q</div><div>deque(['y', 'a', 'b', 'c', 'x'])</div></div><div><span style="-en-paragraph: true;">deque</span><span style="-en-paragraph: true;">除了实现list的</span><span style="-en-paragraph: true;">append()</span><span style="-en-paragraph: true;">和</span><span style="-en-paragraph: true;">pop()</span><span style="-en-paragraph: true;">外，还支持</span><span style="-en-paragraph: true;">appendleft()</span><span style="-en-paragraph: true;">和</span><span style="-en-paragraph: true;">popleft()</span><span style="-en-paragraph: true;">，这样就可以非常高效地往头部添加或删除元素。</span></div><div><font style="font-size: 12pt; color: rgb(28, 51, 135);"><b>常用方法：deque、append、appendleft、clear、count、extend、extendleft、pop、popleft、remove、reverse、rotate</b></font></div><div><span style="-en-paragraph: true;"><br/></span></div><h3><font style="font-size: 12pt; color: rgb(227, 0, 0);">defaultdict</font></h3><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">使用</span><span style="-en-paragraph: true;">dict</span><span style="-en-paragraph: true;">时，如果引用的Key不存在，就会抛出</span><span style="-en-paragraph: true;">KeyError</span><span style="-en-paragraph: true;">。如果希望key不存在时，返回一个默认值，就可以用</span><span style="-en-paragraph: true;">defaultdict</span><span style="-en-paragraph: true;">：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; from collections import defaultdict</div><div>&gt;&gt;&gt; dd = defaultdict(lambda: 'N/A')</div><div>&gt;&gt;&gt; dd['key1'] = 'abc'</div><div>&gt;&gt;&gt; dd['key1'] # key1存在'abc'</div><div>&gt;&gt;&gt; dd['key2'] # key2不存在，返回默认值</div><div>'N/A'</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">注意默认值是调用函数返回的，而函数在创建</span><span style="-en-paragraph: true;">defaultdict</span><span style="-en-paragraph: true;">对象时传入。</span></div><div><span style="-en-paragraph: true;">除了在Key不存在时返回默认值，</span><span style="-en-paragraph: true;">defaultdict</span><span style="-en-paragraph: true;">的其他行为跟</span><span style="-en-paragraph: true;">dict</span><span style="-en-paragraph: true;">是完全一样的。</span></div><div><span style="-en-paragraph: true;"><br/></span></div><div><span style="-en-paragraph: true;"><br/></span></div><h3><font style="font-size: 12pt; color: rgb(227, 0, 0);">OrderedDict</font></h3><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">使用</span><span style="-en-paragraph: true;">dict</span><span style="-en-paragraph: true;">时，Key是无序的。在对</span><span style="-en-paragraph: true;">dict</span><span style="-en-paragraph: true;">做迭代时，我们无法确定Key的顺序。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">如果要保持Key的顺序，可以用</span><span style="-en-paragraph: true;">OrderedDict</span><span style="-en-paragraph: true;">：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; from collections import OrderedDict</div><div>&gt;&gt;&gt; d = dict([('a', 1), ('b', 2), ('c', 3)])</div><div>&gt;&gt;&gt; d # dict的Key是无序的</div><div>{'a': 1, 'c': 3, 'b': 2}</div><div>&gt;&gt;&gt; od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])</div><div>&gt;&gt;&gt; od # OrderedDict的Key是有序的</div><div>OrderedDict([('a', 1), ('b', 2), ('c', 3)])</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">注意，</span><span style="-en-paragraph: true;">OrderedDict</span><span style="-en-paragraph: true;">的Key会按照插入的顺序排列，不是Key本身排序：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; od = OrderedDict()</div><div>&gt;&gt;&gt; od['z'] = 1</div><div>&gt;&gt;&gt; od['y'] = 2</div><div>&gt;&gt;&gt; od['x'] = 3</div><div>&gt;&gt;&gt; od.keys() # 按照插入的Key的顺序返回</div><div>['z', 'y', 'x']</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">OrderedDict</span><span style="-en-paragraph: true;">可以实现一个FIFO（先进先出）的dict，当容量超出限制时，先删除最早添加的Key：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>from collections import OrderedDict</div><div><br/></div><div>class LastUpdatedOrderedDict(OrderedDict):</div><div><br/></div><div>    def __init__(self, capacity):</div><div>        super(LastUpdatedOrderedDict, self).__init__()</div><div>        self._capacity = capacity</div><div><br/></div><div>    def __setitem__(self, key, value):</div><div>        containsKey = 1 if key in self else 0</div><div>        if len(self) - containsKey &gt;= self._capacity:</div><div>            last = self.popitem(last=False)</div><div>            print 'remove:', last</div><div>        if containsKey:</div><div>            del self[key]</div><div>            print 'set:', (key, value)</div><div>        else:</div><div>            print 'add:', (key, value)</div><div>        OrderedDict.__setitem__(self, key, value)</div></div><div><br/></div><div><br/></div><h3><font style="font-size: 12pt; color: rgb(227, 0, 0);">Counter</font></h3><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">Counter</span><span style="-en-paragraph: true;">是一个简单的计数器，例如，统计字符出现的个数：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>&gt;&gt;&gt; from collections import Counter</div><div>&gt;&gt;&gt; c = Counter()</div><div>&gt;&gt;&gt; for ch in 'programming':</div><div>...     c[ch] = c[ch] + 1</div><div>...</div><div>&gt;&gt;&gt; c</div><div>Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})</div></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;">Counter</span><span style="-en-paragraph: true;">实际上也是</span><span style="-en-paragraph: true;">dict</span><span style="-en-paragraph: true;">的一个子类，上面的结果可以看出，字符</span><span style="-en-paragraph: true;">'g'</span><span style="-en-paragraph: true;">、</span><span style="-en-paragraph: true;">'m'</span><span style="-en-paragraph: true;">、</span><span style="-en-paragraph: true;">'r'</span><span style="-en-paragraph: true;">各出现了两次，其他字符各出现了一次。</span></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><ul><li><span style="line-height: 1.45;">Counter 获取各元素的个数,返回字典: print(Counter(s)) # Counter({'c': 4, 'b': 4, 'a': 3})</span><br/></li><li><span style="line-height: 1.45;">most_common(int) 按照元素出现的次数进行从高到低的排序,返回前int个元素的字典</span><br/></li><li>elements 返回经过计数器Counter后的元素,返回的是一个迭代器</li><li>update 和set集合的update一样,对集合进行并集更新</li><li>substract 和update类似，只是update是做加法，substract做减法,从另一个集合中减去本集合的元素</li></ul></div><div style="-en-paragraph: true; margin-top: 1em; margin-bottom: 1em;"><span style="-en-paragraph: true;"><br/></span></div><h3>小结</h3><div><span style="-en-paragraph: true;">collections</span><span style="-en-paragraph: true;">模块提供了一些有用的集合类，可以根据需要选用。</span></div></div></span>
</div></body></html> 